/**
 *tab.js
 *@des 不需要显示调用插件，在某些动作开始或结束时能提供callback或者是触发相应的事件。
 */
(function($) {
    function Tab(element) {
        this.element = $(element)
    }

    Tab.prototype.show = function() {
        var $this = this.element,
            $parentLi = $this.parent(),
            //tab 可能是个dropdown中的元素
            $parentUl = $this.closest('ul:not(.dropdown)')
        if ($parentLi.hasClass('active')) {
            return
        }

        //在这里要搞点事件让外面的知道，如果没有active的tab，就不会有hideEvent。
        var $previous = $parentUl.find('> .active a'),
            hideEvent = $.Event('hide.bs.tab', {
                relatedTarget: $this[0]
            }),
            showEvent = $.Event('show.bs.tab', {
                relatedTarget: $previous[0]
            })
        $previous.trigger(hideEvent)
        $this.trigger(showEvent)

        //如果监听的函数不需要继续执行，e.preventDefault()
        if (hideEvent.isDefaultPrevented() || showEvent.isDefaultPrevented()) {
            return
        }
        var selector = $this.data('target')
        if (!selector) {
            selector = $this.attr('href')
        }
        selector = $(selector)

        /**
         *将activate动作提取到这里
         */
        this.activate($parentLi, $parentUl)
        this.activate(selector, selector.parent(), function() {
            $previous.trigger($.Event('hidden.bs.tab', {
                relatedTarget: $this[0]
            }))
            $this.trigger($.Event('shown.bs.tab', {
                relatedTarget: $previous[0]
            }))
        })
    }

    Tab.prototype.activate = function(element, container, callback) {
        var $active = container.find('> .active'),
            transition = $.support.transition && callback && $active.length && $active.hasClass('fade')
        if (element.hasClass('active')) {
            return
        }

        function next() {
            element.addClass('active')
                .find('[data-toggle="tab"]')
                .attr('aria-expanded', true)

            $active.removeClass('active')
                .find('> .dropdown-menu > .active')
                .removeClass('active')
                .end()
                .find('[data-toggle="tab"]')
                .attr('aria-expanded', false)
            if (transition) {
                element[0].offsetWidth // force to reflow
                element.addClass('in')
            } else {
                //如果不支持transition，而又加了fade，那就去掉
                element.removeClass('fade')
            }
            if (element.parent('.dropdown-menu')) {
                element.closest('li.dropdown')
                    .addClass('active')
                    .end()
                    .find('[data-toggle="tab"]')
                    .attr('aria-expanded', true)
            }
            callback && callback()
        }
        $active.length && transition ? $active.one('bsTransitionEnd', next) : next()
        $active.removeClass('in')
    }

    function Plugin(option) {
        $(this).each(function() {
            var data = $(this).data('bs.tab')
            if (!data) {
                $(this).data('bs.tab', (data = new Tab(this)))
            }
            if (typeof option == 'string') {
                data[option]()
            }
        })
    }

    //handle conflict
    var origin = $.fn.tab
    $.fn.tab = Plugin

    //每个插件还通过 Constructor 属性暴露了其原始的构造函数
    $.fn.tab.Constructor = Tab
    $.fn.tab.noConflict = function() {
        $.fn.tab = origin
        return this
    }

    //使用document代理点击事件，即高效又易于解绑。事件类型采用了特殊的命名空间，易于按照类型解绑，也适合全局开关事件。
    function clickHandler(e) {
        e.preventDefault()
        Plugin.call(this, 'show') //为何这里要写‘show’，因为你点一个tab一定是想显示这个tab。
    }

    /**
     * 根据data-toggle标记调用，只需要加个标记。但如果要显式调用
     * $('#myTab a').click(function (e) {
     *  e.preventDefault()
     *  $(this).tab('show')
     * })
     * each tab needs to be activated individually
     * 每个tab通过记录tabpanel的id，查询active状态的tabpanel来控制tabpanel的显示和消失。有几个tab就需要几个Tab instance。
     * 这里最大的问题是必须要点击后才能调用，其目的就是节约资源。但是，如果这里的tab切换效果是左右或上下滑动，就不方便实现。
     * 因此需要借用carousel.js这个轮播插件，来实现。BootStrap的插件就像是精简的积木一样，可以组合使用。
     */
    $(document).on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)

}(jQuery));
